﻿namespace Resonator.Core.Services
{
	using System;
	using System.Collections.Generic;
	using System.Globalization;
	using System.IO;
	using ICSharpCode.SharpZipLib.Zip;
	using Models;
	using Resonator.Domain.Models;
	using Resonator.Domain.Services;

	public class ZipResourceExporter : IResourceExporter
	{
		private readonly IResourceExporter _inner;

		public ZipResourceExporter()
			: this( new ResxResourceExporter() )
		{
		}

		public ZipResourceExporter(IResourceExporter inner)
		{
			if( inner == null )
			{
				throw new ArgumentNullException( "inner" );
			}

			_inner = inner;
		}

		public virtual void Export(Stream stream, IEnumerable<Resource> resources)
		{
			Export( stream, resources );
		}

		public virtual void Export(Stream stream, IEnumerable<Resource> resources, CultureInfo defaultCulture)
		{
			Dictionary<string, CultureResources> sortedResources = new Dictionary<string, CultureResources>();

			foreach( Resource resource in resources )
			{
				string fileName = CreateFileNameFromResource( resource, resource.Culture );
				CultureResources cultureResources;
				if( !sortedResources.TryGetValue( fileName, out cultureResources ) )
				{
					cultureResources = new CultureResources( resource.Culture );
					sortedResources.Add( fileName, cultureResources );
				}
				cultureResources.Resources.Add( resource );

				foreach( Translation translation in resource.Translations )
				{
					fileName = CreateFileNameFromResource( resource, translation.Culture );
					if( !sortedResources.TryGetValue( fileName, out cultureResources ) )
					{
						cultureResources = new CultureResources( resource.Culture );
						sortedResources.Add( fileName, cultureResources );
					}
					cultureResources.Resources.Add( resource );
				}
			}

			using( ZipOutputStream zipStream = new ZipOutputStream( new NoCloseStream( stream ) ) )
			{
				foreach( string fileName in sortedResources.Keys )
				{
					zipStream.PutNextEntry( new ZipEntry( fileName ) );
					_inner.Export( zipStream, sortedResources[fileName].Resources, sortedResources[fileName].Culture );
					zipStream.CloseEntry();
				}
				zipStream.Finish();
			}
		}

		protected virtual string CreateFileNameFromResource(Resource resource, CultureInfo culture)
		{
			string fileName = resource.Name;
			int fileNameIndex = fileName.IndexOf( '.' );
			if( fileNameIndex >= 0 )
			{
				fileName = fileName.Substring( 0, fileNameIndex );
			}
			if( culture != CultureInfo.InvariantCulture )
			{
				fileName = string.Concat( fileName, ".", culture.Name );
			}
			fileName = string.Concat( fileName, _inner.Extension );
			return fileName;
		}

		public virtual string Extension
		{
			get { return ".zip"; }
		}

		protected class CultureResources
		{
			public readonly CultureInfo Culture;
			public readonly List<Resource> Resources = new List<Resource>();

			public CultureResources(CultureInfo culture)
			{
				Culture = culture;
			}
		}
	}
}